package util

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mp4/entity"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	default_Chromedp_Sleep = 30
	Default_Sleep_value    = 30 * time.Second
	PAGECOUNT              = 100000
)

func ReadConfigs(basePath string, path string, entities []entity.DownloadEntity) []entity.DownloadEntity {
	files, _ := ioutil.ReadDir(path)

	for _, f := range files {
		if f.IsDir() {
			tempPath := CombinationFielPath(path, f.Name())
			entities = ReadConfigs(basePath, tempPath, entities)
		} else if strings.HasSuffix(f.Name(), ".config.json") {
			configPath := CombinationFielPath(path, f.Name())
			entity := ReadConfig(configPath)

			entity.FileDirPath = strings.ReplaceAll(entity.FileDirPath, "//", "/")
			if strings.Index(entity.FileDirPath, ":/") == -1 {
				entity.AbsolutePath = basePath + "/" + entity.FileDirPath
			} else {
				entity.AbsolutePath = entity.FileDirPath
			}

			entities = append(entities, entity)
		}
	}
	return entities
}

func CombinationFielPath(path string, name string) string {
	var configPath string
	if strings.Index(path, "/") > 0 {
		configPath = path + "/" + name
		//configPath = strings.ReplaceAll(configPath, "\\\\", "/")
		//configPath = strings.ReplaceAll(configPath, "\\", "/")
	} else {
		configPath = path + "/" + name
		//configPath = strings.ReplaceAll(configPath, "/", "\\")
	}
	return configPath
}

// 读取json配置文件
func ReadConfig(path string) entity.DownloadEntity {
	log.Println("[" + path + "]")
	f, _ := os.Open(path)
	defer f.Close()
	buf := make([]byte, 1024)
	var chunk []byte
	//builder := strings.Builder{}

	for {
		//从file读取到buf中
		n, _ := f.Read(buf)
		//说明读取结束
		if n == 0 {
			break
		}
		//读取到最终的缓冲区中
		chunk = append(chunk, buf[:n]...)
	}
	var entity entity.DownloadEntity

	json.Unmarshal(chunk, &entity)
	entity.ConfigPath = path
	entity.FileName = f.Name()

	if IsEmpty(entity.FFmpeg) {
		entity.FFmpeg = "ffmpeg"
	}
	entity.FFmpeg = strings.ToLower(entity.FFmpeg)
	if IsEmpty(entity.Path7Z) {
		entity.Path7Z = "7z"
	}

	if 0 == entity.ChromedpSleep {
		entity.ChromedeSleep = Default_Sleep_value
	} else {
		entity.ChromedeSleep = time.Duration(entity.ChromedpSleep) * time.Second
	}

	if 0 == entity.Time {
		entity.Time = 120
	}

	if IsEmpty(entity.HtmlContent) {
		entity.HtmlContent = "琅琊榜 第二部 %s \n #因为一个片段看了整部剧 #好剧推荐 #老剧回看 #影视剪辑片段 #国产好剧"
	}

	if IsEmpty(entity.AuthSubmit) {
		entity.AuthSubmit = "python E:/temp/2/social-auto-upload/cli_main.py douyin dykj6f3pcctp upload \"%s\" -pt 0"
	}

	if IsEmpty(entity.BackMusicPath) {
		entity.BackMusicPath = "E:/temp/download/output.mp3"
	}

	if !IsEmpty(entity.FileDirPath) {
		entity.FileDirPath = strings.ReplaceAll(entity.FileDirPath, "\\\\", "//")
		entity.FileDirPath = strings.ReplaceAll(entity.FileDirPath, "\\", "/")
	}

	if IsEmpty(entity.TitleExtract) {
		entity.TitleExtract = "1"
	}

	if IsEmpty(entity.Cover) {
		entity.Cover = "0"
	}

	if IsEmpty(entity.Cover4K) {
		entity.Cover4K = "0"
	}

	if IsEmpty(entity.PlayListChildURLAtt) {
		entity.PlayListChildURLAtt = "href"
	}

	if ExistsDir(entity.FileDirPath) {
		log.Println("--->", entity.FileDirPath)

		os.MkdirAll(entity.FileDirPath, os.ModePerm)
	}

	return entity
}

func WriteConfigOfStartIndex(downEntity entity.DownloadEntity, startIndex int, childIndex int) {
	config := ReadConfig(downEntity.ConfigPath)

	f, error := os.Create(downEntity.ConfigPath)
	defer f.Close()

	if nil != error {
		log.Println("文件读取失败", error.Error())
		return
	}

	encoder := json.NewEncoder(f)

	config.StartIndex = startIndex

	config.ChildURLIndex = childIndex
	config.ConfigPath = ""
	config.FileName = ""

	error = encoder.Encode(config)
	if error != nil {
		log.Println("编码错误", error.Error())
	}
}

/*判断文件夹是否存在*/
func ExistsDir(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return os.IsNotExist(err)
	}
	return !s.IsDir()
}

/*判断文件夹是否存在*/
func ExistsFile(path string, config entity.DownloadEntity) bool {
	s, err := os.Stat(path)
	if err != nil {
		flag := os.IsExist(err)
		if flag {
			return ValidateFileFFmpeg(path, config)
		}
		return false
	}
	if s.Size() == 0 {
		return false
	}

	if strings.HasSuffix(path, ".mp4") {
		return ValidateFileFFmpeg(path, config)
	}

	return s.IsDir()
}

func IsFile(target string) bool {
	if _, err := os.Stat(target); err == nil {
		fmt.Println("File exists ", target)
		return true
	} else {
		fmt.Println("File does not exist", target)
		return false
	}
}

func WriteFile(fileName string, url string, resp *http.Response) bool {
	if nil == resp {
		log.Println(fileName, "http response error :", url, "-->", resp)
		return false
	}

	if nil == resp.Body {
		log.Println(fileName, "http response body error :", url, "-->", resp.Status)
		return false
	}

	out, error := os.Create(fileName)
	defer func() {
		if nil != out {
			out.Close()
			out = nil
		}
	}()
	if nil != error {
		log.Println(fileName, "create File error :", url, "-->", error)
		return false
	}
	_, writeError := io.Copy(out, resp.Body)
	if nil != writeError {
		log.Println(fileName, "write File error :", url, "-->", error)
		return false
	}
	return true
}

func IdentifyImpage(path string, config entity.DownloadEntity) (bool, string) {
	files, _ := ioutil.ReadDir(path)
	length := len(files)
	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".ts.ts.ts") {
			continue
		} else if strings.HasSuffix(f.Name(), ".ts.ts") {
			continue
		} else if strings.HasSuffix(f.Name(), ".ts") {
			imagePaths := SegmentationJPG(path, f.Name(), config)
			var texts1 []string
			nameIndex := strings.Index(f.Name(), ".ts")
			title := f.Name()
			nameVal, _ := strconv.Atoi(title[0:nameIndex])
			for _, imagePath := range imagePaths {
				result := HttpImage(imagePath, path, imagePath, path+"/"+f.Name())

				_, texts1 = SwitchOCR(result, config.Violation, imagePaths, imagePath, texts1, nameVal > length-100, config)
				if strings.HasSuffix(imagePath, ".jpg") {
					os.Remove(imagePath)
				}
			}
		} else if strings.HasSuffix(f.Name(), ".jpg") {
			os.Remove(path + "/" + f.Name())
		}
	}

	files, _ = ioutil.ReadDir(path)
	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".jpg") {
			os.Remove(path + "/" + f.Name())
		}
	}

	return true, path
}

func HttpImage(path string, parentPath string, imageTitle string, tsPath string) entity.HttpResult {
	var httResult entity.HttpResult
	file, err := os.Open(path)
	if err != nil {
		err = errors.New("获取本地图片失败")
		return httResult
	}
	defer file.Close()
	imgByte, _ := ioutil.ReadAll(file)

	postStr := strings.NewReader("{\"base64\":\"" + base64.StdEncoding.EncodeToString(imgByte) + "\"}")

	req, _ := http.NewRequest("POST", "http://127.0.0.1:1224/api/ocr", postStr)

	req.Header.Add("Content-Type", "application/json")

	response, err := http.DefaultClient.Do(req)
	defer response.Body.Close()
	if nil != err {
		log.Println("请启动ocr")
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return httResult
	}
	str := string(body)

	json.Unmarshal(body, &httResult)
	if err != nil {
		log.Println("JSON ERR:", err, str)
	}

	httResult.Index, _ = strconv.Atoi(imageTitle[strings.LastIndex(imageTitle, "/")+1 : strings.LastIndex(imageTitle, "_")])
	httResult.PATH = path
	httResult.ParentPath = parentPath
	httResult.TsPath = tsPath

	return httResult
}

func SwitchOCR(result entity.HttpResult, violation []string, imagePaths []string, titleStr string, texts1 []string, endFlag bool, config entity.DownloadEntity) (bool, []string) {
	datas := result.Data
	lenData := len(datas)

	start := 0
	end := 0
	count := 0
	var texts []string
	var oldText []string
	for i := 0; i < lenData; i++ {
		violationLength := len(violation)
		flag := true
		oldText = append(oldText, result.Data[i].Text)
		for j := 0; j < violationLength; j++ {
			if result.Data[i].Text == violation[j] || strings.Index(result.Data[i].Text, violation[j]) > -1 || strings.Index(violation[j], result.Data[i].Text) > -1 {
				if IsCover(config.Cover) {
					if result.Data[i].Score > 0.7 {
						length1 := len(result.Data[i].Box)
						x := result.Data[i].Box[0][0]
						y := result.Data[i].Box[0][1]
						maxX := result.Data[i].Box[0][0]
						maxY := result.Data[i].Box[0][1]
						for k := 0; k < length1; k++ {
							if (result.Data[i].Box[k][0]) < x {
								x = result.Data[i].Box[k][0]
							}

							if result.Data[i].Box[k][1] < y {
								y = result.Data[i].Box[k][1]
							}

							if result.Data[i].Box[k][0] > maxX {
								maxX = result.Data[i].Box[k][0]
							}

							if result.Data[i].Box[k][1] > maxY {
								maxY = result.Data[i].Box[k][1]
							}
						}
						Conver(result.TsPath, x, y, maxX-x+10, maxY-y, config)
					}

				} else {
					count++
					flag = false
					break
				}

			}
		}

		if flag {
			strs := []rune(result.Data[i].Text)
			for _, r := range strs {
				val := string(r)
				switch val {
				case "第":
					if switchVal(val, texts1) {
						start++
						flag = false
						texts1 = append(texts1, val)
					}
				case "集":
					if switchVal(val, texts1) {
						start++
						flag = false
						texts1 = append(texts1, val)
					}
				case "演":
					if switchVal(val, texts1) && endFlag {
						end++
						flag = false
						texts1 = append(texts1, val)
					}
				case "职":
					if switchVal(val, texts1) && endFlag {
						end++
						flag = false
						texts1 = append(texts1, val)
					}
				case "人":
					if switchVal(val, texts1) && endFlag {
						end++
						flag = false
						texts1 = append(texts1, val)
					}
				case "员":
					if switchVal(val, texts1) && endFlag {
						end++
						flag = false
						texts1 = append(texts1, val)
					}
				case "表":
					if switchVal(val, texts1) && endFlag {
						end++
						flag = false
						texts1 = append(texts1, val)
					}

				}
			}
		}

		if flag {
			texts = append(texts, result.Data[i].Text)
		}
	}

	chooseFlag := true
	if start >= 2 {
		chooseFlag = false
		removeStart(result)
	} else if end >= 2 {
		chooseFlag = false
		removeEnd(result)
	} else if count > 2 {
		chooseFlag = false
		removeTs(result)
		removeFile(imagePaths)
	} else {
		log.Println(texts, result.Data, count, result.Index, titleStr, "==>")

	}
	return chooseFlag, texts1
}

func switchVal(val string, texts []string) bool {
	length := len(texts)
	if length == 0 {
		return true
	}

	for i := 0; i < length; i++ {
		if texts[i] == val {
			return false
		}
	}
	return true
}
func removeStart(result entity.HttpResult) bool {

	for i := 0; i <= result.Index; i++ {
		path := result.ParentPath + "/" + formatTitle1(i, 8) + ".ts"
		err := os.Remove(path)
		if err != nil {
			log.Println(err)
		}
	}
	return true
}

func removeEnd(result entity.HttpResult) bool {
	for i := result.Index; i < 100+result.Index; i++ {
		path := result.ParentPath + "/" + formatTitle1(i, 8) + ".ts"
		err := os.Remove(path)

		if err != nil {
			log.Println(err)
			break
		}
	}
	return true
}

func removeTs(result entity.HttpResult) bool {
	path := result.TsPath
	err := os.Remove(path)
	if err != nil {
		log.Println(err)
	}
	return true
}

func removeFile(imagePaths []string) bool {
	for _, imagePath := range imagePaths {
		os.Remove(imagePath)
	}
	return true
}

func formatTitle1(index int, length int) string {
	builder := strings.Builder{}
	len := length - len(fmt.Sprintf("%d", index))
	for i := 0; i < len; i++ {
		builder.WriteString("0")
	}
	builder.WriteString(fmt.Sprintf("%d", index))
	return builder.String()
}

func WriterTxt(path string) (bool, string) {

	files, _ := ioutil.ReadDir(path)
	filePath := path + "/content.txt"
	file, err := os.Create(filePath)
	defer file.Close()
	if err != nil {
		log.Println("无法创建文件：", err)
		return false, ""
	}

	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".ts") {
			file.WriteString("file '" + path + "/" + f.Name() + "'\n")
		}
	}

	return true, filePath
}

func WriterTxtTip(path string, text string) (bool, string) {
	file, err := os.Create(path)
	defer file.Close()
	if err != nil {
		log.Println("无法创建文件：", err)
		return false, ""
	}

	file.WriteString(text)

	return true, path
}

func WriterArrayTip(path string, text []string) (bool, string) {
	file, err := os.Create(path)
	defer file.Close()
	if err != nil {
		log.Println("无法创建文件：", err)
		return false, ""
	}

	for _, t := range text {
		file.WriteString(t + "\n")
	}

	return true, path
}

func switchName(path string, name string) []string {
	var names []string
	files, _ := ioutil.ReadDir(path)
	str := name[0:strings.LastIndex(name, ".")]
	for _, f := range files {
		if strings.HasPrefix(f.Name(), str+"_") {
			names = append(names, path+"/"+f.Name())
		}
	}
	return names
}

func switchNameType(path string, typeStr string) []string {
	var names []string
	files, _ := ioutil.ReadDir(path)

	for _, f := range files {
		if strings.HasSuffix(f.Name(), typeStr) {
			names = append(names, path+"/"+f.Name())
		}
	}
	return names
}

func IsCover(val string) bool {
	return "1" == val
}

func WriteSend(paths []string, path string) bool {
	// 指定文件路径
	filePath := path + "/send.txt"
	log.Println("[{}] send path", filePath)

	// 打开文件，使用O_WRONLY和O_APPEND标志
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0666)
	defer file.Close()
	if err != nil {
		return WriteFile1(filePath, paths)
	}
	// 确保在函数结束时关闭文件

	// 创建一个带缓存的Writer
	write := bufio.NewWriter(file)

	for i := range paths {
		write.WriteString(paths[i] + "\r\n")
	}

	// 将缓存中的内容写入文件
	write.Flush()
	return true
}
func WriteFile1(path string, paths []string) bool {
	file, _ := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0664)
	defer file.Close()

	writer := bufio.NewWriter(file)
	for i := range paths {
		writer.Write([]byte(paths[i] + "\r\n"))
	}

	writer.Flush()
	return true
}
